package cn.fintecher.pangolin.service.dataimp.service;

import cn.fintecher.pangolin.common.annotation.ExcelAnno;
import cn.fintecher.pangolin.common.enums.ExportTemplateType;
import cn.fintecher.pangolin.common.enums.ImportTemplateType;
import cn.fintecher.pangolin.common.exception.BadRequestException;
import cn.fintecher.pangolin.common.model.PropertyResponse;
import cn.fintecher.pangolin.common.model.UserModel;
import cn.fintecher.pangolin.common.utils.BeanUtils;
import cn.fintecher.pangolin.common.utils.MD5;
import cn.fintecher.pangolin.common.utils.SaxParseExcelUtil;
import cn.fintecher.pangolin.common.utils.ZWDateUtil;
import cn.fintecher.pangolin.entity.elastic.*;
import cn.fintecher.pangolin.service.dataimp.elastic.ExportTemplateElastic;
import cn.fintecher.pangolin.service.dataimp.elastic.ImportTemplateElastic;
import cn.fintecher.pangolin.service.dataimp.model.ExportCaseModel;
import cn.fintecher.pangolin.service.dataimp.model.ExportPhoneModel;
import cn.fintecher.pangolin.service.dataimp.model.ExportWorkOrderModel;
import cn.fintecher.pangolin.service.dataimp.model.request.CheckTemplateRequest;
import cn.fintecher.pangolin.service.dataimp.model.request.ImportExcelConfigParseRequest;
import cn.fintecher.pangolin.service.dataimp.model.response.CheckTemplateResponse;
import cn.fintecher.pangolin.service.dataimp.model.response.ExportFollowRecordModel;
import cn.fintecher.pangolin.service.dataimp.model.response.ImportExcelConfigParseResponse;
import cn.fintecher.pangolin.service.dataimp.request.*;
import cn.fintecher.pangolin.service.dataimp.response.*;
import com.querydsl.core.BooleanBuilder;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.modelmapper.ModelMapper;
import org.modelmapper.TypeToken;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.*;

/**
 * @Auther: xiaqun
 * @Description:
 * @Date: 10:29 2019/8/24
 */

@Service("importTemplateService")
@Transactional(rollbackFor = Exception.class)
public class TemplateCommonService {
    @Autowired
    private BaseService baseService;

    @Autowired
    private ImportTemplateElastic importTemplateElastic;

    @Autowired
    private ExportTemplateElastic exportTemplateElastic;

    @Autowired
    private ModelMapper modelMapper;

    /**
     * 多条件案件查询模板
     */
    public Page<FindImportTemplateResponse> findAllImportTemplate(FindImportTemplateRequest request, Pageable pageable, String token) {
        UserModel userModel = baseService.getUserByToken(token);
        BoolQueryBuilder builder = request.getBuilder();
        baseService.spliceBuilder(builder, userModel);
        SortBuilder sortBuilder = SortBuilders.fieldSort("operateTime").unmappedType("date").order(SortOrder.DESC);
        SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(builder).withPageable(pageable).withSort(sortBuilder).build();
        Page<ImportTemplate> page = importTemplateElastic.search(searchQuery);
        return page.map(e -> modelMapper.map(e, FindImportTemplateResponse.class));
    }

    /**
     * 解析excel表头
     */
    public List<AnalyzeExcelResponse> analyzeExcelTitle(AnalyzeExcelRequest request) throws Exception {
        InputStream inputStream = baseService.getFile(request.getFileId());
        Map<Integer, List<Map<String, String>>> dataMap = SaxParseExcelUtil.parseExcel(inputStream, request.getTitleStartRow(),
                request.getTitleStartCol(), request.getTitleStartRow(), request.getSheetNumber());
        List<AnalyzeExcelResponse> list = new ArrayList<>();
        for (Map.Entry<Integer, List<Map<String, String>>> map : dataMap.entrySet()) {
            List<Map<String, String>> titleRow = map.getValue();
            for (Map<String, String> cellMap : titleRow) {
                for (Map.Entry<String, String> entry : cellMap.entrySet()) {
                    AnalyzeExcelResponse obj = new AnalyzeExcelResponse();
                    obj.setTitleName(entry.getValue());
                    obj.setCol(entry.getKey());
                    obj.setSheetNumber(map.getKey());
                    list.add(obj);
                }
            }
        }
        return list;
    }

    /**
     * 获取案件字段
     */
    public List<PropertyResponse> getCaseProperty(ImportTemplateType type) {
        List<Class<?>> classList = new ArrayList<>();
        switch (type) {
            case CASE_IMPORT:
            case CASE_UPDATE:
                classList.add(CaseImportModel.class);
                classList.add(PersonalImportModel.class);
                break;
//            case FOLLOW_RECORD_IMPORT:
//                break;
            case BILL_IMPORT:
                classList.add(PaymentRecordModel.class);
                break;
            case PRE_RECORD_IMPORT:
                classList.add(PreRecordModel.class);
                break;
            case WORK_ORDER_IMPORT:
                classList.add(WorkOrderModel.class);
                break;
            case WARNING_IMPORT:
                classList.add(WarningModel.class);
                break;
            case LEAVE_IMPORT:
                classList.add(LeaveCaseModel.class);
                break;
            case STOP_IMPORT:
                classList.add(StopCaseModel.class);
                break;
//            case DISTRIBUTE_IMPORT:
//                classList.add(DistributeImportModel.class);
//                break;
            default:
                throw new BadRequestException(null, "template", "template.type.error");
        }
        return getObjectProperty(classList);
    }

    /**
     * 获取导出字段
     */
    public List<PropertyResponse> getExportProperty(ExportTemplateType type) {
        List<Class<?>> classList = new ArrayList<>();
        switch (type) {
            case CASE:
                classList.add(ExportCaseModel.class);
                break;
            case FOLLOW_RECORD:
                classList.add(ExportFollowRecordModel.class);
                break;
            case WORK_ORDER:
                classList.add(ExportWorkOrderModel.class);
                break;
            case CONTACT:
                classList.add(ExportPhoneModel.class);
                break;
            default:
                throw new BadRequestException(null, "template", "template.type.error");
        }
        return getObjectProperty(classList);
    }

    /**
     * 获取目标类的字段
     */
    private List<PropertyResponse> getObjectProperty(List<Class<?>> objClassList) {
        List<PropertyResponse> responses = new ArrayList<>();
        for (Class<?> objClass : objClassList) {
            //获取类中所有的字段
            Field[] fields = objClass.getDeclaredFields();
            for (Field field : fields) {
                //获取标记了ExcelAnno的注解字段
                if (field.isAnnotationPresent(ExcelAnno.class)) {
                    ExcelAnno f = field.getAnnotation(ExcelAnno.class);
                    PropertyResponse response = new PropertyResponse();
                    response.setAttribute(field.getName());
                    response.setName(f.cellName());
                    response.setPropertyType(f.fieldType().name());
                    responses.add(response);
                }
            }
        }
        return responses;
    }

    /**
     * 新增模板
     */
    public void addImportTemplate(AddImportTemplateRequest request, String token) {
        UserModel userModel = baseService.getUserByToken(token);
        BoolQueryBuilder booleanBuilder = QueryBuilders.boolQuery();
        booleanBuilder.must(QueryBuilders.matchPhraseQuery("name.keyword", request.getName()))
                .must(QueryBuilders.termsQuery("type.keyword", request.getType().name()))
                .must(QueryBuilders.matchPhraseQuery("principalId.keyword", request.getPrincipalId()));
        Iterable<ImportTemplate> search = importTemplateElastic.search(booleanBuilder);
        if (search.iterator().hasNext()) {
            throw new BadRequestException(null, "", "template.type.is.exists");
        }
        ImportTemplate importTemplate = new ImportTemplate();
        BeanUtils.copyPropertiesIgnoreNull(request, importTemplate);
        importTemplate.setItems(request.getItems());
        importTemplate.setId(UUID.randomUUID().toString().replaceAll("-", ""));
        importTemplate.process(userModel.getRealName(), ZWDateUtil.getNowDateTime(), true);
        importTemplateElastic.save(importTemplate);
    }

    /**
     * 删除模板
     */
    public void deleteTemplate(String templateId) {
        importTemplateElastic.deleteById(templateId);
    }

    /**
     * 获取模板信息
     */
    public ImportTemplate getImportTemplateById(String templateId) {
        return importTemplateElastic.findById(templateId).orElseThrow(() -> new BadRequestException(null, "importTemplate", "template.is.null"));
    }

    /**
     * 修改模板
     */
    public void modifyImportTemplate(ModifyTemplateRequest request, String token) {
        UserModel userModel = baseService.getUserByToken(token);
        ImportTemplate importTemplate = importTemplateElastic.findById(request.getId()).orElseThrow(() -> new BadRequestException(null, "importTemplate", "template.is.null"));
        BoolQueryBuilder booleanBuilder = QueryBuilders.boolQuery();
        booleanBuilder.must(QueryBuilders.matchPhraseQuery("name.keyword", request.getName()))
                .must(QueryBuilders.termsQuery("type.keyword", importTemplate.getType().name()))
                .must(QueryBuilders.matchPhraseQuery("principalId.keyword", importTemplate.getPrincipalId()))
                .mustNot(QueryBuilders.matchPhraseQuery("id.keyword", request.getId()));
        Iterable<ImportTemplate> search = importTemplateElastic.search(booleanBuilder);
        if (search.iterator().hasNext()) {
            throw new BadRequestException(null, "", "template.type.is.exists");
        }
        importTemplate.setName(request.getName());
        importTemplate.setTitleStartRow(request.getTitleStartRow());
        importTemplate.setTitleStartCol(request.getTitleStartCol());
        importTemplate.setDataStartRow(request.getDataStartRow());
        importTemplate.setDataStartCol(request.getDataStartCol());
        importTemplate.setSheetNumber(request.getSheetNumber());
        importTemplate.setItems(request.getItems());
        importTemplate.process(userModel.getRealName(), ZWDateUtil.getNowDateTime(), false);
        importTemplateElastic.save(importTemplate);
    }

    /**
     * 查询委托方下模板
     */
    public List<TemplateResponse> getTemplateByPrincipal(String principalId, ImportTemplateType type) {
        List<ImportTemplate> list = importTemplateElastic.findAllByPrincipalIdAndType(principalId, type);
        Type listType = new TypeToken<List<TemplateResponse>>() {
        }.getType();
        return modelMapper.map(list, listType);
    }


    /**
     * 解析Excel数据模板头信息
     */
    public CheckTemplateResponse checkTemplate(CheckTemplateRequest request) throws Exception {
        CheckTemplateResponse response = new CheckTemplateResponse();
        List<String> resultList = new ArrayList<>();
        List<String> insertResultList = new ArrayList<>();
        Optional<ImportTemplate> optional = importTemplateElastic.findById(request.getId());
        if (!optional.isPresent()) {
            throw new BadRequestException(null, "checkTemplate", "template.not.exist");
        }
        ImportTemplate importTemplate = optional.get();
        List<ImportTemplateItem> oldItem = importTemplate.getItems();
        //先按sheetNum排序,再按列号排序
        oldItem.sort(Comparator.comparing(ImportTemplateItem::getSheetNumber).thenComparing(obj ->
                SaxParseExcelUtil.excelColStrToNum(obj.getCol(), obj.getCol().length())));
        Map<String, ImportTemplateItem> oldItemMap = new HashMap<>();
        oldItem.forEach(importTemplateItem -> oldItemMap.put(MD5.MD5Encode(String.valueOf(importTemplateItem.getSheetNumber()).
                concat(importTemplateItem.getCol())), importTemplateItem));
        ImportExcelConfigParseRequest request1 = new ImportExcelConfigParseRequest();
        BeanUtils.copyProperties(request, request1);
        List<ImportExcelConfigParseResponse> responses = parserTemplateHeader(request1);
        Map<String, ImportExcelConfigParseResponse> newItemMap = new HashMap<>();
        responses.forEach(parseResponse -> newItemMap.put(MD5.MD5Encode(String.valueOf(parseResponse.getSheetNum()).
                concat(parseResponse.getCol())), parseResponse));
        List<ImportTemplateItem> items = new ArrayList<>();
        //检测两次模板的匹配度
        newItemMap.forEach((key, value) -> {
            ImportTemplateItem item = oldItemMap.get(key);
            if (oldItemMap.containsKey(key)) {
                if (!oldItemMap.get(key).getTitleName().equals(value.getTitleName())) {
                    resultList.add("sheet页[".concat(String.valueOf(value.getSheetNum())).concat(" ]旧值[")
                            .concat(oldItemMap.get(key).getTitleName())
                            .concat(" ] 新值[").concat(value.getTitleName()).concat("]"));
                    item.setTitleName(value.getTitleName());
                    items.add(item);
                } else {
                    items.add(item);
                }
            } else {
                insertResultList.add("sheet页[".concat(String.valueOf(value.getSheetNum())).concat("] 列号[")
                        .concat(value.getCol())
                        .concat("] 标题名称[").concat(value.getTitleName()).concat("]"));
                ImportTemplateItem newItem = new ImportTemplateItem();
                newItem.setAttribute("");
                newItem.setTitleName(value.getTitleName());
                newItem.setCol(value.getCol());
                newItem.setSheetNumber(value.getSheetNum());
                newItem.setPropertyType(value.getSheetNum().compareTo(Integer.parseInt("1")) == 0 ?
                        ExcelAnno.FieldType.CASE.name() : ExcelAnno.FieldType.PERSONAL.name());
                items.add(newItem);
            }
        });
        response.setInsertResultList(insertResultList);
        items.sort(Comparator.comparing(ImportTemplateItem::getSheetNumber).thenComparing(obj ->
                SaxParseExcelUtil.excelColStrToNum(obj.getCol(), obj.getCol().length())));
        response.setItems(items);
        response.setResultList(resultList);
        response.setFileId(request.getFileId());
        return response;
    }

    /**
     * 解析Excel数据模板头信息
     */
    public CheckTemplateResponse checkExportTemplate(CheckTemplateRequest request) throws Exception {
        CheckTemplateResponse response = new CheckTemplateResponse();
        List<String> resultList = new ArrayList<>();
        List<String> insertResultList = new ArrayList<>();
        Optional<ExportTemplate> optional = exportTemplateElastic.findById(request.getId());
        if (!optional.isPresent()) {
            throw new BadRequestException(null, "checkTemplate", "template.not.exist");
        }
        ExportTemplate exportTemplate = optional.get();
        List<ExportTemplateItem> oldItem = exportTemplate.getItems();
        //先按sheetNum排序,再按列号排序
        oldItem.sort(Comparator.comparing(ExportTemplateItem::getSheetNumber).thenComparing(obj ->
                SaxParseExcelUtil.excelColStrToNum(obj.getCol(), obj.getCol().length())));
        Map<String, ExportTemplateItem> oldItemMap = new HashMap<>();
        oldItem.forEach(exportTemplateItem -> oldItemMap.put(MD5.MD5Encode(String.valueOf(exportTemplateItem.getSheetNumber()).
                concat(exportTemplateItem.getCol())), exportTemplateItem));
        ImportExcelConfigParseRequest request1 = new ImportExcelConfigParseRequest();
        BeanUtils.copyProperties(request, request1);
        List<ImportExcelConfigParseResponse> responses = parserTemplateHeader(request1);
        Map<String, ImportExcelConfigParseResponse> newItemMap = new HashMap<>();
        responses.forEach(parseResponse -> newItemMap.put(MD5.MD5Encode(String.valueOf(parseResponse.getSheetNum()).
                concat(parseResponse.getCol())), parseResponse));
        List<ExportTemplateItem> items = new ArrayList<>();
        //检测两次模板的匹配度
        newItemMap.forEach((key, value) -> {
            ExportTemplateItem item = oldItemMap.get(key);
            if (oldItemMap.containsKey(key)) {
                if (!oldItemMap.get(key).getTitleName().equals(value.getTitleName())) {
                    resultList.add("sheet页[".concat(String.valueOf(value.getSheetNum())).concat(" ]旧值[")
                            .concat(oldItemMap.get(key).getTitleName())
                            .concat(" ] 新值[").concat(value.getTitleName()).concat("]"));
                    item.setTitleName(value.getTitleName());
                    items.add(item);
                } else {
                    items.add(item);
                }
            } else {
                insertResultList.add("sheet页[".concat(String.valueOf(value.getSheetNum())).concat("] 列号[")
                        .concat(value.getCol())
                        .concat("] 标题名称[").concat(value.getTitleName()).concat("]"));
                ExportTemplateItem newItem = new ExportTemplateItem();
                newItem.setAttribute("");
                newItem.setTitleName(value.getTitleName());
                newItem.setCol(value.getCol());
                newItem.setSheetNumber(value.getSheetNum());
                newItem.setPropertyType(value.getSheetNum().compareTo(Integer.parseInt("1")) == 0 ?
                        ExcelAnno.FieldType.CASE.name() : ExcelAnno.FieldType.PERSONAL.name());
                items.add(newItem);
            }
        });
        response.setInsertResultList(insertResultList);
        items.sort(Comparator.comparing(ExportTemplateItem::getSheetNumber).thenComparing(obj ->
                SaxParseExcelUtil.excelColStrToNum(obj.getCol(), obj.getCol().length())));
        response.setExportItems(items);
        response.setResultList(resultList);
        response.setFileId(request.getFileId());
        return response;
    }

    /**
     * 解析模板头文件
     */
    private List<ImportExcelConfigParseResponse> parserTemplateHeader(ImportExcelConfigParseRequest importExcelConfigParseRequest) throws Exception {
        List<ImportExcelConfigParseResponse> importExcelConfigParseResponseList = new ArrayList<>();
        String fileId = importExcelConfigParseRequest.getFileId();
        InputStream inputStream = baseService.getFile(fileId);
        Map<Integer, List<Map<String, String>>> dataMap = SaxParseExcelUtil.parseExcel(inputStream, importExcelConfigParseRequest.getTitleStartRow(),
                importExcelConfigParseRequest.getTitleStartCol(), 1, importExcelConfigParseRequest.getSheetTotals());
        for (Map.Entry<Integer, List<Map<String, String>>> map : dataMap.entrySet()) {
            List<Map<String, String>> titleRow = map.getValue();
            for (Map<String, String> cellMap : titleRow) {
                for (Map.Entry<String, String> entry : cellMap.entrySet()) {
                    ImportExcelConfigParseResponse obj = new ImportExcelConfigParseResponse();
                    obj.setTitleName(entry.getValue());
                    obj.setCol(entry.getKey());
                    obj.setSheetNum(map.getKey());
                    importExcelConfigParseResponseList.add(obj);
                }
            }
        }
        //排序
        importExcelConfigParseResponseList.sort(Comparator.comparing(ImportExcelConfigParseResponse::getSheetNum).thenComparing(obj -> SaxParseExcelUtil.excelColStrToNum(obj.getCol(), obj.getCol().length())));
        return importExcelConfigParseResponseList;
    }

    /**
     * 多条件查询导出模板
     */
    public Page<FindExportTemplateResponse> findAllExportTemplate(FindExportTemplateRequest request, Pageable pageable, String token) {
        UserModel userModel = baseService.getUserByToken(token);
        BoolQueryBuilder builder = request.getBuilder();
        baseService.spliceBuilder(builder, userModel);
        SortBuilder sortBuilder = SortBuilders.fieldSort("operateTime").unmappedType("date").order(SortOrder.DESC);
        SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(builder).withPageable(pageable).withSort(sortBuilder).build();
        Page<ExportTemplate> page = exportTemplateElastic.search(searchQuery);
        return page.map(e -> modelMapper.map(e, FindExportTemplateResponse.class));
    }

    /**
     * 新增导出模板
     */
    public void addExportTemplate(AddExportTempalteRequest request, String token) {
        List<ExportTemplate> existsList = exportTemplateElastic.findAllByPrincipalIdAndTypeAndName(request.getPrincipalId(), request.getType(), request.getName());
        if (existsList.size() > 0) {
            throw new BadRequestException(null, "addExportTemplate", "template.type.is.exists");
        }
        UserModel userModel = baseService.getUserByToken(token);
        ExportTemplate exportTemplate = new ExportTemplate();
        BeanUtils.copyPropertiesIgnoreNull(request, exportTemplate);
        exportTemplate.setItems(request.getItems());
        exportTemplate.setId(UUID.randomUUID().toString().replaceAll("-", ""));
        exportTemplate.process(userModel.getRealName(), ZWDateUtil.getNowDateTime(), true);
        exportTemplateElastic.save(exportTemplate);
    }

    /**
     * 删除导出模板
     */
    public void deleteExportTemplate(String templateId) {
        exportTemplateElastic.deleteById(templateId);
    }

    /**
     * 获取导出模板信息
     */
    public ExportTemplate getExportTemplateById(String templateId) {
        return exportTemplateElastic.findById(templateId).orElseThrow(() -> new BadRequestException(null, "exportTemplate", "template.is.null"));
    }

    /**
     * 修改导出模板
     */
    public void modifyExportTemplate(ModifyExportTemplateRequest request, String token) {
        UserModel userModel = baseService.getUserByToken(token);
        ExportTemplate exportTemplate = exportTemplateElastic.findById(request.getId()).orElseThrow(() -> new BadRequestException(null, "exportTemplate", "template.is.null"));
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder.must(QueryBuilders.termsQuery("principalId.keyword", exportTemplate.getPrincipalId()))
                .must(QueryBuilders.termsQuery("type.keyword", exportTemplate.getType().name()))
                .must(QueryBuilders.termsQuery("name.keyword", request.getName()))
                .mustNot(QueryBuilders.termsQuery("id.keyword", exportTemplate.getId()));
        Iterable<ExportTemplate> search = exportTemplateElastic.search(boolQueryBuilder);
        if (search.iterator().hasNext()) {
            throw new BadRequestException(null, "modifyExportTemplate", "template.type.is.exists");
        }
        exportTemplate.setName(request.getName());
        exportTemplate.setTitleStartCol(request.getTitleStartCol());
        exportTemplate.setTitleStartRow(request.getTitleStartRow());
        exportTemplate.setDataStartRow(request.getDataStartRow());
        exportTemplate.setSheetNumber(request.getSheetNumber());
        exportTemplate.setDataStartCol(request.getDataStartCol());
        exportTemplate.setPublicField(request.getPublicField());
        exportTemplate.setItems(request.getItems());
        exportTemplate.process(userModel.getRealName(), ZWDateUtil.getNowDateTime(), false);
        exportTemplateElastic.save(exportTemplate);
    }

    /**
     * 查询委托方下导出模板
     */
    public List<TemplateResponse> getExportTemplateByPrincipal(String principalId, ExportTemplateType type) {
        List<ExportTemplate> list = exportTemplateElastic.findAllByPrincipalIdAndType(principalId, type);
        Type listType = new TypeToken<List<TemplateResponse>>() {
        }.getType();
        return modelMapper.map(list, listType);
    }
}
